#ifndef TB_REFLECTION_LUA_REGISTER_HPP__
#define TB_REFLECTION_LUA_REGISTER_HPP__

#include "tbcore/base/result.hpp"

#include "reflection_export.hpp"
#include "reflection_fwd.hpp"

TB_NAMESPACE_BEGIN

namespace lua {

enum TableType {
	kClassTable,
	kVariantTable,
	kMemFunctionTable,
	kPureFunctionTable,
	kUnknownTable,
};

typedef struct {
	Variant* data;
	const reflection::Function* func;
} MemFunctionType;

typedef struct {
	const reflection::Function* func;
} PureFunctionType;

typedef int(*LuaFunctionT) (void* L);

TB_REFLECTION_API void* NewLuaState();
TB_REFLECTION_API void DeleteLuaState(void *l);
TB_REFLECTION_API void InitializeLuaState(void* l);
TB_REFLECTION_API TableType GetUserDataType(void* l, int idx);
TB_REFLECTION_API int GetStackSize(void* l);
TB_REFLECTION_API Variant GetStackValue(void* l, int idx);
TB_REFLECTION_API void PushStackValue(void* l, const Variant& val);
TB_REFLECTION_API Variant GetReturnValue(void* l);
TB_REFLECTION_API Result EvalString(void* l, const String& str);

TB_REFLECTION_API void NewClassMetatable(void* l, const TCHAR* classname,
  LuaFunctionT newproc, LuaFunctionT getproc, LuaFunctionT setproc);
TB_REFLECTION_API void NewVariantMetatable(void* l);
TB_REFLECTION_API void NewMemFunctionMetatable(void* l);
TB_REFLECTION_API void NewPureFunctionMetatable(void* l);

TB_REFLECTION_API void PushClassMetatable(void* l, const TCHAR* classname);
TB_REFLECTION_API void PushVariantMetatable(void* l);
TB_REFLECTION_API void PushMemFunctionMetatable(void* l);
TB_REFLECTION_API void PushPureFunctionMetatable(void* l);

typedef const TB_NAMESPACE::reflection::Function* (*GetClassFunctionT)(const TCHAR* funcName);
typedef const TB_NAMESPACE::reflection::Property* (*GetClassPropertyT)(const TCHAR* propName);

TB_REFLECTION_API int ImplementNewProc(void* l, const TCHAR* className, const Variant& instance);
TB_REFLECTION_API int ImplementGetProc(void* l, GetClassFunctionT funGetter, GetClassPropertyT propGetter);
TB_REFLECTION_API int ImplementSetProc(void* l, GetClassFunctionT funGetter, GetClassPropertyT propGetter);

} //namespace lua

TB_NAMESPACE_END

#define TB_ENSURE_STACK_CLEAR(l) \
  TB_ASSERT(TB_NAMESPACE::lua::GetStackSize((void*)l) == 0 && "luad stack must be cleaned up")

#endif // TB_REFLECTION_LUA_REGISTER_HPP__
